package br.com.zynger.mst.addressbook;

import static org.junit.Assert.*;

import org.junit.BeforeClass;
import org.junit.Test;

public class AddressBookTest {

	static AddressBook addressBook;
	static Person personJulio;
	static Person personZelda;
	static Person personGeorge;
	
	/**
	 * Instantiation of the address book and some persons.
	 */
	@BeforeClass
	public static void init(){
		addressBook = new AddressBook();
		
		personJulio = new Person("Julio", "Zynger",
				"127 North Bishop Ave.", "Rolla",
				"MO", "5739547845", "65401");
		
		personZelda = new Person("Zelda", "Zynger",
				"127 North Bishop Ave.", "Rolla",
				"MO", "5738547125", "65401");
		
		personGeorge = new Person("George", "Gopher",
				"Tunnel 37", "Hamilton",
				"MA", "4214685555", "01936");
		
	}
	
	/**
	 * Test if the result of an addition to
	 * the address book's entries list is
	 * <code>true</code> - meaning that the
	 * person was added successfully.
	 * */
	@Test
	public void testAddPerson() {
		assertTrue(addressBook.addPerson(personJulio));
	}
	
	/**
	 * Add a person, and then remove it.
	 * If the result of the removal is 
	 * <code>true</code>, that means that
	 * the operation was done successfully.*/
	@Test
	public void testRemovePersonSuccessfully() {
		addressBook.addPerson(personJulio);
		assertTrue(addressBook.removePerson(personJulio));
	}
	
	/**
	 * This test will try to remove a
	 * person who is not in the address book's
	 * entry list. This way, the return of
	 * the method should be <code>false</code>.
	 * */
	@Test
	public void testRemovePersonFail() {
		addressBook.addPerson(personJulio);
		assertFalse(addressBook.removePerson(personGeorge));
	}
	
	/**
	 * This test will add a person to
	 * the address book, alter one of its
	 * attributes and then call <code>editPerson()</code>
	 * to edit it in the address book's entry
	 * list.
	 * After that, the person will be looked for
	 * in the list to compare if the attribute
	 * was really updated.
	 * 
	 * @see AddressBook.editPerson()
	 * */
	@Test
	public void testEditPersonSuccessfully() {
		addressBook.getEntries().clear();
		addressBook.addPerson(personJulio);
		personJulio.setAddress("15 Rolla Street");
		addressBook.editPerson(personJulio);
		assertEquals("15 Rolla Street",
				addressBook.getPerson(personJulio.getFirstName(),
				personJulio.getLastName()).getAddress());
	}
	
	/**
	 * This test will try to edit
	 * a person who is not in the address
	 * book entry list. This way, the
	 * result of the method call should
	 * be <code>false</code>.
	 * */
	@Test
	public void testEditPersonFail() {
		Person person = new Person("William", "Bond", "28 Central Street", "St. Louis", "MO", "5734587458", "14587");
		assertFalse(addressBook.editPerson(person));
	}
	
	/**
	 * Test if the search method actually returns
	 * a person based on its first and last name.
	 * 
	 * @see AdressBook.getPerson()
	 * */
	@Test
	public void testSearchPersonSuccessfully() {
		addressBook.getEntries().clear();
		addressBook.addPerson(personJulio);
		assertNotNull(addressBook.getPerson(personJulio.getFirstName(), personJulio.getLastName()));
	}
	
	/**
	 * Test if the search method returns <code>null</code>
	 * when the searched person is not in the
	 * address book entry list.
	 * 
	 * @see AdressBook.getPerson()
	 * */
	@Test
	public void testSearchPersonFail() {
		Person person = new Person("William", "Bond", "28 Central Street", "St. Louis", "MO", "5734587458", "14587");
		assertNull(addressBook.getPerson(person.getFirstName(), person.getLastName()));
	}
	
	/**
	 * Adds two people to the address book,
	 * call the sorting method and then compare
	 * the new order of the address book entries
	 * with a known ordered array.
	 * */
	@Test
	public void testSortByLastName() {
		addressBook.getEntries().clear();
		addressBook.addPerson(personJulio);
		addressBook.addPerson(personGeorge);
		Object[] array = addressBook.getEntries().toArray();
		addressBook.sortByName();
		
		Object[] expected = { personJulio, personGeorge };
		
		assertArrayEquals(expected, array);
	}
	
	/**
	 * Same method of testing as the
	 * sorting based on the last name,
	 * except that this one will treat
	 * the case that last names are equal,
	 * so the first name of the people to
	 * compare should be considered.
	 * 
	 * @see testSortByLastName
	 * */
	@Test
	public void testSortByFirstName() {
		addressBook.getEntries().clear();
		addressBook.addPerson(personJulio);
		addressBook.addPerson(personZelda);
		Object[] array = addressBook.getEntries().toArray();
		addressBook.sortByName();
		
		Object[] expected = { personJulio, personZelda };
		
		assertArrayEquals(expected, array);
	}
	
	/**
	 * Adds two people to the address book,
	 * call the sorting method and then compare
	 * the new order of the address book entries
	 * with a known ordered array.
	 * 
	 * @see testSortByLastName
	 * */
	@Test
	public void testSortByZipCode() {
		addressBook.getEntries().clear();
		addressBook.addPerson(personJulio);
		addressBook.addPerson(personGeorge);
		Object[] array = addressBook.getEntries().toArray();
		addressBook.sortByZipCode();
		
		Object[] expected = { personJulio, personGeorge };
		
		assertArrayEquals(expected, array);
	}
	
}
